import { Inject, Provide } from "@midwayjs/core";
import { Utils } from "../utils";
import { Repository } from "typeorm";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { BblAttach } from "../entity/attach.entity";
import { BblDeskType } from "../entity/desk-type.entity";
import { BblDeskBrand } from "../entity/desk-brand.entity";
import { BblDesk } from "../entity/desk.entity";
import {
  DeskCreateDto,
  DeskInfoDto,
  DeskListQueryDto,
  DeskPageQueryDto,
  DeskListDto,
  DeskWxListDto
} from "../dto/desk.dto";
import { AttachService } from "./att.service";

@Provide()
export class DeskService {
  @Inject()
  utils: Utils;

  /**
   * 附件驱动模型
   */
  @InjectEntityModel(BblAttach)
  attModel: Repository<BblAttach>;

  @Inject()
  attService: AttachService;

  /**
   * 球桌类型驱动模型
   */
  @InjectEntityModel(BblDeskType)
  typeModel: Repository<BblDeskType>;

  /**
   * 品牌驱动模型
   */
  @InjectEntityModel(BblDeskBrand)
  brandModel: Repository<BblDeskBrand>;

  /**
   * 球桌驱动模型
   */
  @InjectEntityModel(BblDesk)
  deskModel: Repository<BblDesk>;

  /**
   * 获取球桌类型列表
   */
  async get_desk_type_list() {
    const typeList = await this.typeModel.find({
      where: {
        deskTypeIsDeleted: 0
      },
      order: {
        deskTypeIndex: "ASC"
      }
    });
    return this.utils.service.success(typeList);
  }

  /**
   * 获取品牌列表
   * @returns
   */
  async get_brand_list() {
    const brandList = await this.brandModel.find({
      where: {
        deskBrandIsDeleted: 0
      },
      order: {
        deskBarndIndex: "ASC"
      }
    });
    return this.utils.service.success(brandList);
  }

  /**
   * 添加球桌
   * @param deskCreateDto
   */
  async add_desk(deskCreateDto: DeskCreateDto) {
    const deskType = await this.typeModel.findOne({
      where: {
        deskTypeId: deskCreateDto.deskTypeId
      }
    });

    if (!deskType) {
      return this.utils.service.fail("球桌类型不存在");
    }

    const deskBrand = await this.brandModel.findOne({
      where: {
        deskBrandId: deskCreateDto.deskBrandId
      }
    });

    if (!deskBrand) {
      return this.utils.service.fail("品牌不存在");
    }

    const deskThumb = await this.attModel.findOne({
      where: {
        attId: deskCreateDto.deskThumbId
      }
    });

    if (!deskThumb) {
      return this.utils.service.fail("缩略图不存在");
    }

    const attIds = deskCreateDto.deskParamImgIds.split(",").map((d) => d);
    const deskParamBuilder = this.attModel
      .createQueryBuilder("att")
      .where("att.attId in (:...attIds)", { attIds });
    const deskParamImgs = await deskParamBuilder.getMany();

    if (deskParamImgs.length === 0 || deskParamImgs.length !== attIds.length) {
      return this.utils.service.fail("请上传正确的参数图片");
    }

    const desk = new BblDesk();
    desk.deskId = this.utils.uuid();
    desk.deskName = deskCreateDto.deskName;
    desk.deskType = deskType;
    desk.deskBrand = deskBrand;
    desk.deskIsDeleted = 0;
    desk.deskPrice = deskCreateDto.deskPrice;
    desk.deskRemark = deskCreateDto.deskRemark;
    desk.deskThumb = deskThumb;
    desk.deskParamImgs = deskParamImgs;
    desk.deskIndex = deskCreateDto.deskIndex || 1;
    const res = await this.deskModel.save(desk);

    // 将临时文件转移到上传文件夹
    await this.attService.tmp_to_uploads([deskThumb, ...deskParamImgs]);

    return this.utils.service.success(res);
  }

  async get_origin_desk(deskId: string) {
    const builder = this.deskModel
      .createQueryBuilder("desk")
      .leftJoinAndSelect("desk.deskType", "deskType")
      .leftJoinAndSelect("desk.deskBrand", "deskBrand")
      .leftJoinAndSelect("desk.deskThumb", "deskThumb")
      .leftJoinAndSelect("desk.deskParamImgs", "deskParamImgs")
      .where("desk.deskIsDeleted = 0 and desk.deskId = :deskId", { deskId });

    const desk = await builder.getOne();
    return desk;
  }

  /**
   * 修改球桌
   * @param deskId
   * @param updateDto
   * @returns
   */
  async update_desk(deskId: string, updateDto: DeskCreateDto) {
    const desk = await this.get_origin_desk(deskId);
    if (!desk) {
      return this.utils.service.fail("球桌不存在");
    } else {
      desk.deskName = updateDto.deskName;
      desk.deskPrice = updateDto.deskPrice;
      desk.deskRemark = updateDto.deskRemark;
      desk.deskIndex = updateDto.deskIndex || 1;

      // 如果球桌类型、品牌、缩略图有变化，则需要重新赋值
      if (desk.deskType.deskTypeId !== updateDto.deskTypeId) {
        const deskType = await this.typeModel.findOne({
          where: {
            deskTypeId: updateDto.deskTypeId
          }
        });
        if (!deskType) {
          return this.utils.service.fail("球桌类型不存在");
        }

        desk.deskType = deskType;
      }

      if (desk.deskBrand.deskBrandId !== updateDto.deskBrandId) {
        const deskBrand = await this.brandModel.findOne({
          where: {
            deskBrandId: updateDto.deskBrandId
          }
        });
        if (!deskBrand) {
          return this.utils.service.fail("品牌不存在");
        }

        desk.deskBrand = deskBrand;
      }

      // 临时文件集合
      const tmpAtts: BblAttach[] = [];

      if (desk.deskThumb.attId !== updateDto.deskThumbId) {
        const deskThumb = await this.attModel.findOne({
          where: {
            attId: updateDto.deskThumbId
          }
        });
        if (!deskThumb) {
          return this.utils.service.fail("缩略图不存在");
        }
        // 删除原来的缩略图
        await this.attModel.remove(desk.deskThumb);
        desk.deskThumb = deskThumb;
        tmpAtts.push(deskThumb);
      }

      // 解析新的参数图片id集合
      const new_param_img_ids = updateDto.deskParamImgIds
        .split(",")
        .map((d) => d);

      // 找到已经不存在的参数图片
      // 删除已经不存在的参数图片
      const files = desk.deskParamImgs.filter(
        (d) => new_param_img_ids.indexOf(d.attId) < 0
      );
      await this.attService.remove(files);

      // 找到新增的参数图片
      const deskParamImgs = await this.attModel
        .createQueryBuilder("att")
        .where("att.attId in (:...attIds)", { attIds: new_param_img_ids })
        .getMany();

      tmpAtts.push(...deskParamImgs);

      // 统一将缩略图和参数图片中的临时文件转移到上传文件夹
      await this.attService.tmp_to_uploads(tmpAtts);

      desk.deskParamImgs = deskParamImgs;

      const res = await this.deskModel.save(desk);
      const deskDto = new DeskInfoDto(res);
      return this.utils.service.success(deskDto);
    }
  }

  async remove_desk(deskId: string) {
    const desk = await this.get_origin_desk(deskId);
    if (!desk) {
      return this.utils.service.fail("球桌不存在");
    }

    desk.deskIsDeleted = 1;

    await this.deskModel.save(desk);

    return this.utils.service.success(desk.deskId);
  }

  async get_desk(deskId: string) {
    const desk = await this.get_origin_desk(deskId);

    if (!desk) {
      return this.utils.service.fail("球桌不存在");
    } else {
      const dto = new DeskInfoDto(desk);
      return this.utils.service.success(dto);
    }
  }

  async get_desk_list(listQueryDto: DeskListQueryDto) {
    const builder = this.deskModel
      .createQueryBuilder("desk")
      .leftJoinAndSelect("desk.deskType", "deskType")
      .leftJoinAndSelect("desk.deskBrand", "deskBrand")
      .where("desk.deskIsDeleted = 0");

    if (listQueryDto.deskName) {
      builder.andWhere("desk.deskName like :deskName", {
        deskName: `%${listQueryDto.deskName}%`
      });
    }

    if (listQueryDto.deskTypeId && listQueryDto.deskTypeId !== "") {
      builder.andWhere("desk.DESK_TYPE_ID = :deskTypeId", {
        deskTypeId: Number(listQueryDto.deskTypeId)
      });
    }

    if (listQueryDto.deskBrandId && listQueryDto.deskBrandId !== "") {
      builder.andWhere("desk.DESK_BRAND_ID = :deskBrandId", {
        deskBrandId: Number(listQueryDto.deskBrandId)
      });
    }

    const desks = await builder.getMany();

    return this.utils.service.success(desks);
  }

  async get_desk_page_list(pageDto: DeskPageQueryDto) {
    const builder = this.deskModel
      .createQueryBuilder("desk")
      .leftJoinAndSelect("desk.deskType", "deskType")
      .leftJoinAndSelect("desk.deskBrand", "deskBrand")
      .where("desk.deskIsDeleted = 0")
      .orderBy("desk.createdAt", "DESC");

    if (pageDto.deskName) {
      builder.andWhere("desk.deskName like :deskName", {
        deskName: `%${pageDto.deskName}%`
      });
    }

    if (pageDto.deskTypeId && pageDto.deskTypeId !== "") {
      builder.andWhere("desk.DESK_TYPE_ID = :deskTypeId", {
        deskTypeId: pageDto.deskTypeId
      });
    }

    if (pageDto.deskBrandId && pageDto.deskBrandId !== "") {
      builder.andWhere("desk.DESK_BRAND_ID = :deskBrandId", {
        deskBrandId: pageDto.deskBrandId
      });
    }

    const total = await builder.getCount();
    builder.skip((Number(pageDto.current) - 1) * Number(pageDto.pageSize));
    builder.take(Number(pageDto.pageSize));
    const result = await builder.getMany();

    const records = result.map((desk) => new DeskListDto(desk));

    return this.utils.service.success({
      total,
      records,
      current: pageDto.current,
      pageSize: pageDto.pageSize
    });
  }

  async get_wxapp_desk_page_list(brandId: string = "") {
    const builder = this.deskModel
      .createQueryBuilder("desk")
      .leftJoinAndSelect("desk.deskType", "deskType")
      .leftJoinAndSelect("desk.deskBrand", "deskBrand")
      .leftJoinAndSelect("desk.deskThumb", "deskThumb")
      .where("desk.deskIsDeleted = 0")
      .orderBy("deskBrand.deskBrandName")
      .addOrderBy("deskType.deskTypeName")
      .addOrderBy("desk.deskPrice", "ASC")
      .addOrderBy("desk.deskIndex", "ASC");

    if (brandId && brandId !== "") {
      builder.andWhere("desk.DESK_BRAND_ID = :deskBrandId", {
        deskBrandId: brandId
      });
    }

    const result = await builder.getMany();

    const records = result.map((desk) => new DeskWxListDto(desk));

    return this.utils.service.success(records);
  }
}
